perm filename MEMO63.PUB[HAL,HE] blob
sn#117124 filedate 1974-08-28 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00008 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 .ctc: NEWSS COMPILE-TIME CONSTRUCTS
C00005 00003 Also, it is frequently useful to be able to specify various sorts of
C00009 00004 .NEWSSS CONDITIONAL EXPANSION
C00013 00005 .NEWSSS THE COMPILE-TIME CHECK STATEMENT
C00021 00006 .NEWSSS COMPILE-TIME PREDICATE FUNCTIONS
C00023 00007 .ctv: NEWSSS COMPILE-TIME VARIABLES
C00035 00008 .lib:NEWSS LIBRARY ROUTINES
C00047 ENDMK
C⊗;
.ctc: NEWSS COMPILE-TIME CONSTRUCTS
.asr: NEWSSS ASSERTIONS
Although the compiler makes an effort to keep track of the expected
runtime state of variables, it sometimes must be given explicit
information about what values a variable might have. For instance,
it is difficult for the compiler to maintain unambiguous planning
values within the THEN and the ELSE parts of conditionals. Therefore,
during each branch, a separate "world" is in effect, stemming from
the world in force before the IF. All variables modified in either
branch have planning value "undefined" at the close of the
conditional. Although eventually the compiler may get smart enough to
resolve a number of such cases, assertions must be used ( at least
for now) to inform the compiler of any planning values it might need
thereafter. For example:
.UNFILL
IF G=1 THEN
BEGIN
ATTACH FROB TO YELLOW;
MOVE FROB TO HOLE;
OPERATE YFINGERS WITH OPENING=5;
DETACH FROB FROM YELLOW;
MOVE YELLOW TO YPARK;
END;
ASSERT YELLOW=YPARK;
.REFILL
The ASSERT statement
tells the compiler to use YPARK as the planning value for YELLOW at
the close of the conditional. In general, information about
variable values may be specified by statements of the form:
.UNFILL
ASSERT <expression> <relation> <constant>
.REFILL
The <relation> must be "=", except where <expression> and <constant> are
scalars, in which case "<",">","≤", and
"%7≥%*" may also be used. At present, <expression> is restricted to be
either a variable name or a linear form involving only scalar
variables. For instance
.UNFILL
ASSERT V = (1 2 3);
ASSERT F1 = α#(T1) * α#(F2);
.COMT 12
α{Recall that T1 is not a constant, but α#(T1) --
ie the current planning value of T1) is. α}
.END
ASSERT 3*S1 + 4*S2 ≤ 3;
.REFILL
Also, it is frequently useful to be able to specify various sorts of
symbolic information which can be used to direct conditional
expansion of various compile-time conditionals and by the various
high level primitives (such as INSERT or GRASP) provided by the
expander. This facility is provided by the construct:
.UNFILL
ASSERT FACT (<pattern>)
.REFILL
where <pattern> may by any sequence of identifiers and constants. For
instance:
.UNFILL
ASSERT FACT (MACHINE TURING);
ASSERT FACT (PAINTED ROSES RED WITH BRUSH);
ASSERT FACT (WEIGHT ENGINE_BLOCK 4.5 POUNDS);
ASSERT FACT (PART1 FITS_ONTO PART2 [(1,2,3):(π,0,π/2)]);
.REFILL
The actual meaning of an asserted pattern is generally determined by
whatever conventions the user may wish to establish. However, a few
pattern types, such as those for attachment or those used by the very
high level routines for object descriptions, are "understood" and
used by the compiler. The user can cause serious confusions by
improper introduction or deletion of such patterns. Generally,
assertions will remain "true" in the compiler's world model until
explicitly deleted or, in the case of assertions used by the
compiler, as a side effect of processing some statement. Any
assertion (whether of a fact or of a relation) may be undone by use
of the DENY construct, which is similar to ASSERT, except for the use
of the word "DENY". Thus, we might have
.UNFILL
DENY V = α#(V);
DENY 4*X-5*Y = 10;
DENY FACT (IN HAND SCREWDRIVER);
.REFILL
Note the use of α#(V) in the first example to retrieve the current
planning value for V. After the denial is processed, α#(V) will
become undefined.
Assertions may be named by inclusion of a "label" field after the
word "ASSERT", as in
.UNFILL
ASSERT "FOO" X = 3.14;
ASSERT "BAZ" 4*X-10*Y %7≥%* 1;
ASSERT "FOOBAZ" FACT(IN HAND HAMMER);
.REFILL
This construct is very useful for deleting an assertion without
having to recall it exactly. For instance,
.UNFILL
DENY "BAZ";
.REFILL
would have the same effect as
.UNFILL
DENY 4*X-10*Y %7≥%* 1;
.REFILL
NOTE: A possible source of confusion is the fact that assertions are
purely a compile-time construct used to direct compilation. It is
not possible to view the assertional structure at runtime.
.NEWSSS CONDITIONAL EXPANSION
It is frequently desirable to write a fairly general piece of source
code that produces different object code, depending on the specific
task to be performed and on the compiler's model of the expected
runtime environment. The principal mechanism provided for this
purpose is the compile-time conditional construct, which behaves like
a conventional Algol "IF", except that it is resolved at compile
time, with only the the "expanded" part having any effect on the
compiler's world model. The syntax is:
.UNFILL
COMPILE IF <condition> THEN
<then-part>
ELSE
<else-part>
.REFILL
where the "ELSE" component may be omitted if desired. The condition
may be any boolean expression involving only constants. For
instance:
.UNFILL
COMPILE IF α#(BLUE)%7≠%*BPARK THEN
MOVE BLUE TO BPARK;
.REFILL
Also, the results of symbolic assertions may be tested by means of
the FACT construct, as in
.UNFILL
COMPILE IF FACT (IN TOOLRACK SCREWDRIVER) THEN
BEGIN
.COMT 20
α{ Code to fetch the screwdriver out
of the tool rackα}
.END
END;
.REFILL
When used in this way, FACT expressions are boolean primaries, and
can enter into more complicated boolean expressions in the usual way.
For instance:
.UNFILL
COMPILE IF FACT(GOES_IN SHAFT1 HOLE1)
∧%7¬%*FACT(IN SHAFT1 HOLE1) THEN
BEGIN
COMPILE IF FACT(THREADED SHAFT1) THEN
BEGIN
.COMT 28
α{ here code to insert a threaded screwα}
.END
ASSERT FACT (SCREWED SHAFT1);
END
ELSE
BEGIN
.COMT 28
α{ here code to insert a smooth pinα}
.END
ASSERT FACT (SLIPPED_IN SHAFT1);
END;
ASSERT FACT (IN SHAFT1 HOLE1);
END;
.REFILL
Frequently, one may want to test a whole class of asserted facts at
once. For instance, suppose we may want to know if the blue hand is
available for some task or another. We can keep track of what is in
the hand by means of assertions like
.UNFILL
ASSERT FACT (BLUE HOLDS WIDGET);
.REFILL
However, it is frequently inconvenient, and sometimes impossible,
explicitly to test all possibilities, as in:
.UNFILL
COMPILE IF %7¬%*FACT(BLUE HOLDS WIDGET)
∧ %7¬%*FACT(BLUE HOLDS FROB) ∧ . . . THEN
BEGIN
comment whatever;
END;
.REFILL
The reserved word ANYTHING is provided as a wild card to avoid this
difficulty. Thus, we can write:
.UNFILL
COMPILE IF %7¬%*FACT(BLUE HOLDS ANYTHING) THEN
BEGIN
comment whatever;
END;
.REFILL
.NEWSSS THE COMPILE-TIME CHECK STATEMENT
Since library routines will be commonly used, it is necessary
to have some way of checking that necessary preconditions are met as
the first steps of the library routine. The way this is done is with
the CHECK statement. A simple example:
.unfill
CHECK X=3 ∧ Y>5
.refill
The contents of the check may be any
boolean expression, including checks on the current world model. The
check is only made at compile-time; if the check is not satisfied,
the compiler will generate an error message.
The effect of this statement is exactly like that of
.UNFILL
COMPILE IF %7¬%*(X=3 ∧ Y>5) THEN
COMPILE_ERROR("CHECK STATEMENT FAILED") .
.REFILL
.NEWSSS BINDING BOOLEANS
Frequently the construct ANYTHING does not suffice. For example,
the user may want to execute different code, depending on what is
supposed to be in the blue hand. Compile-time variables, which are
described more fully in {sssref ctv}, provide a means of doing this.
Such variables have no runtime existence whatsoever. Instead, the
compiler can set their "planning" value to the internal structure
associated with any string of valid tokens in the language. Then,
whenever the parser encounters the "α#(vi)" for compile time variable
vi, it substitutes the associated "value". For instance, suppose
the compile time variable "HAND_ID" has been given (by some means)
the value "YELLOW". Then
.UNFILL
MOVE α#(HAND_ID) TO FOO;
.REFILL
is identical to
.UNFILL
MOVE YELLOW TO FOO;
.REFILL
There are a number of ways (discussed in {sssref ctv}) by which a
compile-time variable may given a value. One of these is the
construct
.UNFILL
BIND(Vi)
.REFILL
in a FACT pattern within a boolean test. BIND(Vi) acts something
like ANYTHING in that it will match any token occurring at a
corresponding place in a pattern. However, it has the additional
effect of setting the planning value of Vi to the corresponding
element in the matched pattern. For instance,
.UNFILL
COMPILE_TIME THING,WHERE;
:
ASSERT FACT (BLUE HOLDS FROB);
ASSERT FACT (CORRECT_SPOT_FOR FROB [(1,2,3):(π,0,0)]);
ASSERT FACT (CORRECT_SPOT_FOR WIDGET [(4,5,6):(π,0,0)]);
:
COMPILE IF FACT(BLUE HOLDS BIND(THING)) THEN
BEGIN
IF FACT (CORRECT_SPOT_FOR α#(THING) BIND(WHERE)) THEN
BEGIN
MOVE BLUE TO α#(WHERE);
comment ... etc ... ;
END
ELSE
BEGIN
comment some sort of error message, perhaps;
END;
END;
.REFILL
Would expand into
.UNFILL
MOVE BLUE TO [(1,2,3):(π,0,0)];
comment ... etc ...;
.REFILL
.NEWSSS COMPILE FOREACH
Sometimes, there may be several assertions in the data base that could
satisfy a given FACT retrieval pattern. For instance,
.UNFILL
ASSERT FACT(S1 SCREWS INTO H1);
ASSERT FACT(S2 SCREWS INTO H2);
ASSERT FACT(S3 SCREWS INTO H3);
:
COMPILE IF FACT(BIND(S) SCREWS INTO BIND(H)) THEN
BEGIN
:
END
.REFILL
In such cases, the compiler would arbitrarily pick one of the
eligible patterns to use as its "template" for performing any
requested bindings. Suppose, however, that the user wants to perform
some action for each pattern that matches, rather than for only one.
For instance, she may want to insert all the screws into their
corresponding holes. The compile-time FOREACH construct is intended
to allow this sort of thing.
.UNFILL
COMPILE FOREACH <condition> DO
<statement>
.REFILL
where the <condition> must have the form
.UNFILL
FACT (<pattern>)
.REFILL
This construct will cause <statement> to be compiled once for each
instance of <pattern> that finds a match in the data base.
For instance, a library routine that fastens down a head to an engine
block
by means of bolts which can be inserted in any order
might include a sequence like:
.UNFILL
COMPILE_TIME BOLT,HOLE_ID,HEAD_ID;
:
COMPILE FOREACH FACT( BIND(BOLT) FASTENS α#(HEAD_ID)) DO
BEGIN
COMPILE IF FACT(α#(BOLT) FITS INTO BIND(HOLE_ID)) THEN
INSERT α#(BOLT) INTO α#(HOLE_ID)
ELSE
BEGIN
COMMENT an error message;
END;
END;
.REFILL
If we then have assertions:
.UNFILL
ASSERT FACT (B1 FASTENS PUMPHEAD);
ASSERT FACT (B2 FASTENS PUMPHEAD);
ASSERT FACT (B3 FASTENS PUMPHEAD);
ASSERT FACT (B1 FITS INTO H1);
ASSERT FACT (B2 FITS INTO H2);
ASSERT FACT (B3 FITS INTO H3);
.REFILL
and call our library routine to put on PUMPHEAD, the above fragment
would expand into
.UNFILL
:
INSERT B1 INTO H1;
INSERT B2 INTO H2;
INSERT B3 INTO H3;
:
.REFILL
.NEWSSS COMPILE-TIME PREDICATE FUNCTIONS
HAL provides several useful predicate functions that are evaluated
at compile-time. One of these is
.UNFILL
SPECIFIED(<routine parameter>)
.REFILL
which may be used inside a routine to tell whether some parameter has been
specified in the call to the routine. (See {ssref lib}). Another is
.UNFILL
HAS_VALUE(<variable>)
.REFILL
which tells whether the <variable> currently has a planning value. For instance,
.UNFILL
SCALAR X,Y,Z;
COMPILE IF %7¬%*HAS_VALUE(X) THEN
BEGIN
ASSERT X=3;
Yα←X;
END;
:
COMPILE IF HAS_VALUE(X) THEN
Zα←α#(X)
ELSE
Zα←5;
.REFILL
would expand into
.UNFILL
SCALAR X,Y,Z;
ASSERT X=3;
Yα←X;
Zα←3;
.REFILL
if X has no planning value.
.ctv: NEWSSS COMPILE-TIME VARIABLES
Compile-time variables in many ways resemble macros, and may (to some
extent) be used as such. The principle difference (but not the only
difference) is that macros work at the text level (i.e., expand into
strings of characters), while compile-time variables work at the
token level. This provides a number of implementation efficiencies,
as well as a nice "hook" for those parts of HAL, such as the pattern
matcher or library routines, that manipulate compiler constructs.
Compile-time variables are declared by the construct
.UNFILL
COMPILE_TIME v1,v2,...,vn;
.REFILL
As mentioned earlier, they have no runtime existence whatsoever.
Instead, the compiler can set their "planning value" to be any string
of tokens in the language. Then, for compile time variable V, the
construct
.UNFILL
α#(V)
.REFILL
produces the same effect as if the current value of V had been
explicitly included in the source program.
We have already discussed one method (the BIND construct) by which a
value may be given to a compile-time variable. The other common way
is the assignment statement:
.UNFILL
<ct var> α← <ct var>
.REFILL
For instance,
.UNFILL
COMPILE_TIME A,B;
:
Aα←B;
COMMENT this causes the planning value of A to
be set to the current planning value of B,
so that, now, α#(A) is the same as α#(B) ;
:
.REFILL
HAL also includes a number of constructs that cause the compiler to
invent a "temporary" compile-time variable containing some token
string as its value. For example, if a body of text appears in macro
delimiters in an "unexpected" place, that is, not in a macro
definition or macro parameter list, then the compiler scans the
enclosed text and builds a compile-time variable (with an unprintable
name) whose value is the resulting token string. Thus if we have
.UNFILL
COMPILE_TIME A;
:
Aα←⊂GO DIRECTLY TO JAIL⊃;
.REFILL
then
.UNFILL
α#(A);
.REFILL
will yield
.UNFILL
GO DIRECTLY TO JAIL;
.REFILL
Note also that
.UNFILL
α#(⊂More garbage⊃)
.REFILL
merely gives
.UNFILL
More garbage
.REFILL
Normally, expansion of the "planning value" construct is turned off
while the delimited text is being tokenized. This allows you to
store things like α#(var) inside a compile-time variable. For
instance,
.UNFILL
COMPILE_TIME FOO,BAZ;
BAZ α← ⊂CENTER α#(FOO)⊃;
:
FOO α← ⊂ YFINGERS ⊃;
α#(BAZ);
:
FOOα← ⊂ BFINGERS ⊃;
α#(BAZ);
.REFILL
This expands into
.UNFILL
CENTER YFINGERS;
:
CENTER BFINGERS;
.REFILL
The construct
.UNFILL
EXPAND(<ct variable>)
.REFILL
produces a new compile-time variable whose value is the "evaluation"
of its argument. The meaning of this is best shown by an example:
.UNFILL
BAZα←⊂CENTER α#(FOO)⊃;
FOOα←⊂YFINGERS⊃;
BARα←EXPAND(BAZ);
.REFILL
gives the same effect as
.UNFILL
BARα←⊂CENTER YFINGERS⊃;
.REFILL
One frequent use of assertions is to specify a number of properties
of some object or variable. For instance,
.UNFILL
ASSERT FACT(HEIGHT widget 100);
ASSERT FACT(WEIGHT widget 200);
ASSERT FACT(DEPROACH widget [(1,2,3)|(π,0,0)]);
.REFILL
These properties may be retrieved by means of a binding boolean, as
in
.UNFILL
COMPILE IF FACT(HEIGHT widget BIND(h)) THEN
BEGIN
MOVE YELLOW TO widget*[(0,0,α#(h)):(0,0,0)];
:
END;
.REFILL
Unfortunately, binding is frequently rather inconvenient as a means for
fetching a single value, since it requires explicit use of an
auxiliary variable. In such cases, the PICK construct can be used
instead, as in
.UNFILL
MOVE YELLOW TO f1
USING WEIGHT=α#(PICK(WEIGHT widget BIND(*)) );
.REFILL
In general, PICK has the form
.UNFILL
PICK(<pattern>)
.REFILL
where <pattern> is just like the FACT patterns discussed in previous
sections, except that it contains "BIND(*)" as one term. PICK causes
the compiler to create a new compile-time variable whose value
corresponds to the BIND(*) term in the matched fact from the data
base. If no value is found then a null value is used. Note that
<pattern> can also contain instances of ANYTHING or BIND(<variable>),
as in:
.UNFILL
ASSERT FACT ( GADGET FITS ONTO WIDGET AT [(0,0,0):(π,0,0)]);
:
OBJα←PICK(GADGET FITS ONTO BIND(*) ANYTHING BIND(LOCN));
.REFILL
which would set the value of OBJ to "WIDGET" and the value of LOCN to
"[(0,0,0):(π,0,0)]".
Another occasionally useful facility is the ability to extract part
of a token stream. HAL provides a number of "subfield" operations to
perform this function. The simplest is
.UNFILL
<ct variable>[<index>]
.REFILL
which creates a new compile-time variable whose value is the
<index>th element of α#(<ct var>). (The exact meaning of "element"
will be discussed in a moment. For the present, "token" may be
substituted.) For example:
.UNFILL
POEM α← ⊂ ARMA VIRUMQUE CANO, TROJAE QUI PRIMUS AB ORIS . . .⊃
:
Bα←POEM[3]; Comment: now α#(B) is "CANO";
.REFILL
Subsequences of elements may be obtained through use of
.UNFILL
<ct variable>[<index> FOR <count>]
.REFILL
and
.UNFILL
<ct variable>[<lower bound> TO <upper bound>]
.REFILL
which do the "obvious" thing. For instance,
.UNFILL
Bα← POEM[2 TO 3]; Comment sets α#(B) to "VIRUMQUE CANO";
Cα← ⊂HIP BONE CONNECTED TO THE THIGH BONE⊃[1 FOR 2];
Comment gives "HIP BONE";
.REFILL
Suppose we want to extract the frame constant from a construct like
.UNFILL
ASR α← ⊂ ASSERT YELLOW = [(0,1,2):(π,0,0)]⊃;
.REFILL
If the extraction operator worked purely on the token level, we'd
have to say something like α#(ASR[4 FOR 19]), which somehow seems a
lot less natural than saying "ASR[4]". To allow for this, the HAL
extraction primitives treat things inside paired "nesting" characters
(⊂⊃,(),[], and α{α}) as single elements. Also, the constructs
BIND(var), PICK(<pattern>), FACT(<pattern>), and INDEX(v1,v2) are all
treated as single elements. Thus
.UNFILL
⊂ A B (C*3) D ⊃[3]
⊂ A + B * C [(X,Y,Z):(π,0,0)] ⊃[6]
⊂ ASSERT FACT(HUMAN TURING) ⊃[2]
⊂ BIND(A) PICK(HUMAN BIND(*)) ANYTHING ⊃[3]
.BULL
expand to
(C*3)
[(X,Y,Z):(π,0,0)]
FACT(HUMAN TURING)
ANYTHING
.REFILL
The same nesting rules apply to FACTs. Thus if we have
.UNFILL
ASSERT FACT( PROPERTIES hammer ⊂WEIGHT x LOCUS (f*y) ⊃);
:
hpropsα←PICK(PROPERTIES hammer BIND(*));
.BULL
then
α#(hprops) expands to ⊂WEIGHT x LOCUS (f*y) ⊃
hprops[4] expands to (f*y)
.REFILL
Note that here α#(hprops) still includes the "⊂ ⊃" and will hence yield
a new compile-time variable.
Another occasionally useful facility is the ability to determine the
index of an element in a string of tokens. This function is
performed by the INDEX primitive:
INDEX(<ct var 1>,<ct var 2>)
which produces an integer constant whose value is the index of the
first occurrence of α#(<ct var 1>) in α#(<ct var 2>). This function is
especially useful in extracting properties from a list. For
instance:
.UNFILL
PROPLα←⊂WEIGHT 1 HEIGHT 200 LOCATION [(1,2,4):(π,0,0)]⊃;
Comment INDEX(⊂HEIGHT⊃,PROPL) = 3 ;
Wα←PROPL[1+INDEX(⊂WEIGHT⊃,PROPL)]; Comment Now α#(W)=1;
.REFILL
.lib:NEWSS LIBRARY ROUTINES
Many of the applications for which HAL is intended characteristicly
involve repeating a number of very similar subtasks. For instance,
an assembly program might have to change sockets on an electric
driver many times in order to drive down a number of different bolts.
If written in "simple" HAL, with each such subtask coded out in
explicit statements like MOVE and OPERATE, such programs would be
very tedious to write and debug. On the other hand, the necessity of
planning motions frequently makes procedures (in the traditional
sense) infeasible. To overcome this difficulty, HAL provides a
facility for "routines", which externally resemble macros, in that
they are "expanded" each time they are invoked, although they are
are stored and manipulated by the compiler in a somewhat more
efficient manner. The HAL system will include a predefined library
of routines for performing a number of commonly useful functions,
although a user can, of course, "roll her own" by using the ROUTINE
construct, which has the form
.UNFILL
ROUTINE <id> (<parameter list>);
<body>
.REFILL
where the <parameter list> syntax is the same as for procedure
definitions, and the <body> may be either an expression or a
statement. When the library routine is expanded, all instances of the
parameter names are substituted with the actual parameters supplied
in the call. Thus, a typical library routine declaration might look
like:
.UNFILL
ROUTINE reach(SCALAR thickness;FRAME place);
BEGIN
.COMT 20
COMMENT causes the hand to move to the indicated
spot, and keep opening & closing its fingers
until something is put in them;
.END
SCALAR flag;
MOVE YELLOW TO place;
flagα←1;
WHILE flag%7≠%*0 DO
BEGIN
OPERATE YFINGERS WITH OPENING = 5;
OPERATE YFINGERS WITH OPENING = thickness-.1
ON YTOUCH DO
BEGIN
flagα←0;
STOP;
END;
END;
END
.REFILL
Library routines without parameters are invoked simply by including
their name in the source program. For instance, suppose we have a
library routine PARK_YELLOW which parks the yellow arm. Then
.UNFILL
IF h>3 THEN
PARK_YELLOW
.REFILL
might expand into something like
.UNFILL
IF h>3 THEN
MOVE YELLOW TO YPARK
.REFILL
There are several ways to specify parameters. Perhaps the
simplest is to follow the syntax for procedure calls, in which case
the arguments must correspond in order and type with those in the
statement which defined the routine. For example,
.UNFILL
reach(0.5, [(1,2,3):(π/2,π/2,0)])
.REFILL
This can become very inconvenient for routines which have a large
number of parameters, since the user may have trouble remembering the
correct order, or may want to leave some unspecified. These
difficulties are avoided by using the form
.UNFILL
reach(thickness = 0.5, place = [(1,2,3):(π/2,π/2,0)])
.REFILL
It is possible to specify default values for parameters to library
routines by including the construct
.UNFILL
(DEFAULT <value>)
.REFILL
after the parameter name in the formal parameter list for the routine.
For example,
.UNFILL
ROUTINE reach(FRAME arm(DEFAULT YELLOW),place;
SCALAR thickness(DEFAULT 0));
BEGIN
:
END
:
reach(BLUE,f1); comment a thickness of 0 is assumed;
reach(place=f2,thickness=10); comment YELLOW arm assumed;
.REFILL
The construct
.UNFILL
SPECIFIED(<parameter id>)
.REFILL
may be used in a compile-time conditional to test whether the named
parameter has been assigned a value. For example,
.UNFILL
ROUTINE transmogrify(COMPILE_TIME errdev;...);
BEGIN
.COMT 20
COMMENT Note here that the compile-time variable
errdev is merely being used as a name
passing mechanism. I.e., we aren't
saying α#(errdev) anywhere. ;
.END
:
IF errcond THEN
BEGIN
COMPILE IF SPECIFIED(errdev) THEN
OPERATE errdev
ELSE
ABORT;
END;
:
END;
.REFILL
If a parameter has no default value specified and is not bound by the
call, then any expansion of the routine that uses the parameter will
result in an error; occurrences of an unbound parameter in the unexpanded
part of a compile time conditional are legal.
Yet another syntax is acceptable for invocation of library routines;
it is included for compatibility with high level primitives (see
{secref vhl}). In this form, the parameter names act like key words
identifying various clauses in a "pseudo-english" statement, as in
.UNFILL
REACH thickness 0.5 place [(1,2,3):(π/2,π/2,0)];
.REFILL
If a parameter to a routine occurs in the body in some construct
where a variable must occur (eg. the left hand side of an assignment
statement), the compiler will do the "right" thing when the
corresponding actual parameter is a constant or expression: a
warning will be printed, and the compiler will invent a temporary
variable to hold the value.
.NEWSSS SAVING LIBRARY ROUTINES
Library routines may be saved on a file by use of the statement (and
supervisor command)
.UNFILL
SAVE <flag> <routine name list> ON <file specifier>
.REFILL
where <flag> may be either NEW, OLD, or <empty>. For instance,
.UNFILL
SAVE reach, transmogrify ON "FEE.FIE[FO,FUM]";
SAVE OLD foobaz ON "DEFS.1[II,HE]";
SAVE NEW grab1, grab2, grab3 ON "GRABS";
.REFILL
IF <flag> is <empty> and one of the named routines already exists on
the specified file, the old definition is overwritten. IF <flag> is
NEW, then only routines which do not already exist on the specified
file will be added. Similarly, if <flag> is OLD then only routines
which are already on the file will be saved. If the <routine name
list> is omitted, then all existing routines will be saved on the
specified file. E.g.
.UNFILL
SAVE ON "DEFS.ALL";
SAVE NEW ON "DEFS.2";
.REFILL
Library routines may be retrieved from a file by the command
.UNFILL
RETRIEVE <flag> <routine name list> FROM <file specifier>
.REFILL
If <flag> is empty, then the specified routines will be retrieved
from the specified file. If, however, <flag> is NEW, then only
routines which are not already defined will be read in; if <flag> is
OLD, then only routines which are already defined will be retrieved
(they will be redefined). If the <routine name list> is <empty>,
then all routines on the file will be read (subject to any
restrictions imposed by <flag>). Examples:
.UNFILL
RETRIEVE FROM "DEFS.RCB";
RETRIEVE Aeneas, Dido FROM "CAVE";
RETRIEVE NEW FROM "HAL.LIB[HAL,HE]";
.REFILL
.NEWSSS SAVING AND RESTORING PLANNING VALUES
The statement SAVE WORLD ON W1 will cause the "world" at
that point in the planning to be written out into a file called
W1.WLD. The statement RETRIEVE WORLD FROM W1 will read in this file
and set up the world as it was when saved.
The world includes all planning values and all assertions. It does
not include defined library routines.
Saving the world is particularly
useful for recovering when the arm runs into trouble; it makes it
unnecessary to begin the planning from scratch.
It is also possible
to improve the planning values of frames after a period of execution;
this is done by the statement RESTORE WORLD FROM RUNTIME.
The effect of this is that all the variables which the runtime knows
about are read, and their values become the new planning values
for those variables.